10. Parallel Streams

Parallel Streams

In this section, you'll learn how to process collections of data using parallel streams.

ND079 JPND C2 L05 A11 Parallel Streams

What are Parallel Streams?

Parallel streams are a way to execute stream pipelines in parallel, on multiple threads.

They can often be a quick way to add parallelism to existing, sequential stream pipeline.

Using Parallel Streams

You use parallel streams by calling the parallelStream() on a Java collection, or by calling the parallel() method on an existing Stream. Here's a non-parallel Stream example from the lesson on Functional Programming:

Map<Year, Long> graduatingClassSizes = studentList
    .stream()
    .collect(Collectors.groupingBy(
        Student::getGraduationYear, Collectors.counting());

Here is a parallel version of the same Stream:

Map<Year, Long> graduatingClassSizes = studentList
    .parallelStream()
    .collect(Collectors.groupingByConcurrent(
        Student::getGraduationYear, Collectors.counting());

Notice also how a concurrent Collector needs to be used. Not all collectors support concurrency; if you accidentally apply such a collector to a parallel stream, the stream will not actually run in parallel.

What can the following code print?

Stream.of("a", "b", "c").parallel().forEachOrdered(System.out::print);
SOLUTION:
  • `abc`

Using Parallel Streams with Thread Pools

By default, parallel streams run threads in the default ForkJoinPool.commonPool(). You can circumvent that default by wrapping the stream computation in a Callable and submitting it to a ForkJoinPool explicitly:

ForkJoinPool pool = new ForkJoinPool();
Future<Map<Year, Long>> graduatingClassSizes = pool.submit(() ->
    studentList.parallelStream()
    .collect(Collectors.groupingByConcurrent(
        Student::getGraduationYear, Collectors.counting()));

This can come in handy if you want finer control over the parallelism, or if you want to separate your parallel stream conputations into different thread pools.

Further Reading